/*  File Name	: Daemon.cpp
 *  Author		: Pang Jiacai
 *	 E-mail		: 823960168@qq.com
 *  Created on	: 2012-6-29
 *  Description:
 */
#include <string.h>
#include "Daemon.h"
#include "Acceptor.h"
#include "EpollReactor.h"
#include "SockAcceptor.h"
#include "Service.h"
#include "TimerTest.h"
#include "ServiceProcess.h"
#include "Configurator.h"
#include "MySqlDB.h"

Daemon *Daemon::instance_ = NULL;

Daemon *Daemon::instance(void)
{
	if(NULL==instance_)
	{
		instance_ = new Daemon();
	}
	return instance_;
}

Daemon::Daemon()
{
	this->process_manager_ = NULL;
	this->is_shutdown_ = true;
}

Daemon::~Daemon()
{
	DELETE(this->process_manager_);
}

void Daemon::register_signal(void)
{
	for(int i=1;i<32;i++)
	{
		if(i==SIGSEGV || i==SIGCHLD)
		{
			continue;
		}
		this->reactor()->register_signal(i,this);
	}
}

int Daemon::handle_signal(int signum)
{
	LOG((INFO_LOG,"Daemon::handle_signal[%d]",signum));
	switch(signum)
	{
		case SIGNAL_GAME_STOP:
		{
			this->stop_game();
			this->is_shutdown_ = true;
			return 0;
		}
		case SIGNAL_STOP_SERVER:
		{
			break;
		}
		case SIGNAL_NEW_SERVER:
		{
			break;
		}
		default:
		{
			break;
		}
	}
	return 0;
}

int Daemon::handle_exit(int pid)
{
	LOG((INFO_LOG,"Daemon::handle_exit pid:[%d][%d]",pid,this->is_shutdown_));
	if(!this->is_shutdown_)
	{
		Process *pro = this->process_manager_->find_process(pid);
		if(NULL==pro)
		{
			LOG((ERROR_LOG,"Daemon::handle_exit can't find pid:[%d]",pid));
			return 0;
		}
		this->spawn_child(pro->type(),pro->line());
	}
	this->process_manager_->remove_process(pid);

	return 0;
}

int Daemon::start_game(int argc,char *argv[])
{
	CONFIG_INSTANCE->load_config();

#ifdef DEBUG
	start_debug_version(argc,argv);
#else
	start_online_version(argc,argv);
#endif
	return 0;
}

int Daemon::stop_game(void)
{
	if(NULL!=this->process_manager_)
	{
		LOG((INFO_LOG,"Daemon::stop_game"));
		this->process_manager_->stop_all_child_process();
	}
	//this->reactor()->end_reactor_loop();
	return 0;
}

int Daemon::start_debug_version(int argc,char *argv[])
{
	this->reactor(Reactor::instance());
	Logger::instance()->open();

	const Json::Value &daemon = CONFIG_INSTANCE->daemon()["debug"];

	for (int i = 0; i < (int) daemon.size(); i++)
	{
		std::string server = daemon[i].asString();
		if (server == DBSERVER)
		{
			ServiceProcess::instance()->start_dbserver(0);
		}
		else if (server == SANDBOX)
		{
			ServiceProcess::instance()->start_sandbox();
		}
		else if (server == ENGINE_SERVICE)
		{
			ServiceProcess::instance()->start_engine(0);
		}
		else if (server == CHAT_SERVICE)
		{
			ServiceProcess::instance()->start_chat(0);
		}
		else if (server == DIRCSERVER)
		{
			ServiceProcess::instance()->start_dircserver(0);
		}
		else if (server == GATE_SERVICE)
		{
			ServiceProcess::instance()->start_gateway(0);
		}
	}
	return this->reactor()->run_reactor_loop();
}

int Daemon::start_online_version(int argc,char *argv[])
{
	if(argc < 3)
	{
		Logger::instance()->open("daemon");

		LOG((INFO_LOG,"Daemon::start_online_version-->daemon"));

		//CONFIG_INSTANCE->load_config();

		Reactor::instance()->implement(new EpollReactor(1024,1024));
		this->reactor(Reactor::instance());

		if(this->process_manager_!=NULL)
		{
			LOG((ERROR_LOG,"daemon process is already start"));
			return 0;
		}
		this->process_manager_ = new ProcessManager(this->reactor());
		this->start_daemon(argc,argv);
	}
	else
	{
		ServiceProcess::instance()->start_service(argc,argv);
	}
	Logger::instance()->stop_logger();
	sleep(2);
	return 0;
}

int Daemon::start_daemon(int argc,char *argv[])
{
	this->register_signal();
	this->start_service(argc,argv);
	this->is_shutdown_ = false;

	//this->reactor()->run_reactor_loop();
	this->reactor()->implement()->run_status(1);
	//int ret = 0;
	while (true)
	{
		//LOG((DEBUG_LOG," Daemon::start_daemon[%d][%d]",
		//		this->is_shutdown_,this->process_manager_->has_child()));
		if (this->is_shutdown_) //&& !this->process_manager_->has_child())
		{
			sleep(8);
			this->reactor()->end_reactor_loop();
			break;
		}
		this->reactor()->handle_events();
	}
	LOG((INFO_LOG,"Daemon main thread exit"));
	return 0;
}

int Daemon::start_service(int argc,char *argv[])
{
	const Json::Value &daemon= CONFIG_INSTANCE->daemon()["online"];

	for(int i=0;i<(int)daemon.size();i++)
	{
		std::string server = daemon[i].asString();
		if(server == DBSERVER)
		{
			const Json::Value &db = CONFIG_INSTANCE->dbserver()["online"];
			for(int i=0;i<(int)db.size();i++)
			{
				this->spawn_child(DBSERVER,i);
			}
		}
		else if(server == SANDBOX)
		{
			const Json::Value &sandbox = CONFIG_INSTANCE->sandbox()["online"];
			for(int i=0;i<(int)sandbox.size();i++)
			{
				this->spawn_child(SANDBOX,i);
			}
		}
		else if(server == ENGINE_SERVICE)
		{
			const Json::Value &engine = CONFIG_INSTANCE->engine()["online"];
			for(int i=0;i<(int)engine.size();i++)
			{
				this->spawn_child(ENGINE_SERVICE,i);
			}
		}
		else if(server == CHAT_SERVICE)
		{
			const Json::Value &chat = CONFIG_INSTANCE->chat()["online"];
			for(int i=0;i<(int)chat.size();i++)
			{
				this->spawn_child(CHAT_SERVICE,0);
			}
		}
		else if(server == DIRCSERVER)
		{
			const Json::Value &dirc = CONFIG_INSTANCE->dircserver()["online"];
			for(int i=0;i<(int)dirc.size();i++)
			{
				this->spawn_child(DIRCSERVER,i);
			}
		}
		else if(server == GATE_SERVICE)
		{
			const Json::Value &gate = CONFIG_INSTANCE->gateway()["online"];
			for(int i=0;i<(int)gate.size();i++)
			{
				this->spawn_child(GATE_SERVICE,i);
			}
		}
	}
	return 0;
}

int Daemon::spawn_child(std::string type,int index)
{
	std::string program="./"+type+"/"+type;

	char line[10]={0};
	sprintf(line,"%d",index);

	char *argv[5]={NULL};
	argv[0]=(char*)program.c_str();
	argv[1]=(char*)type.c_str();
	argv[2]=line;
	argv[3]=(char*)"poker";

	int pid =this->process_manager_->spawn((char*)program.c_str(),argv);
	LOG((INFO_LOG,"Daemon::spawn_child:[%d][%s:%d]",pid,program.c_str(),index));
	if(pid<0)
	{
		LOG((ERROR_LOG,"Daemon::spawn_child failed:[%s:%d]",program.c_str(),index));
		return -1;
	}
	this->process_manager_->register_handler(this,pid);
	sleep(2);
	return 0;
}


